/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tpcomp2010.estructura;

import com.jgraph.layout.JGraphFacade;
import com.jgraph.layout.organic.JGraphOrganicLayout;
import java.awt.Color;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.BorderFactory;
import java.util.ArrayList;

import java.util.Map;
import org.jgraph.JGraph;
import org.jgraph.graph.*;

/**
 * Modificado por Tania Nuñez, Victor Ayala.
 */

public class Grafo extends JGraph {

    // Lista de cells que se agregan al jgraph
    private ArrayList<DefaultGraphCell> cells;
    int width = 40, height = 40;
    private Automata automata;

    public Grafo(Automata a, DefaultGraphModel model) {
        super(model);
        this.automata = a;

        convertirJgraph();
        miLayout();
    }

    /**
     * METODO PRINCIPAL PARA CONVERTIR EL AUTOMATA(nodos, arcos) A LOS
     * ELEMENTOS DE UN JGRAPH
     */
    private void convertirJgraph() {

        //Borramos todo lo que habia en cells y creamos uno nuevo 
        cells = new ArrayList<DefaultGraphCell>();

        for (Nodo elNodo : automata.getNodos()) {
            incluirAristasNodo(elNodo);
        }

        Object[] elementosObj = cells.toArray();
        //DefaultGraphCell[] elementos = (DefaultGraphCell[]) cells.toArray();

        // Control-drag should clone selection
        setCloneable(true);

        // Enable edit without final RETURN keystroke
        setInvokesStopCellEditing(true);

        // When over a cell, jump to its default port (we only have one, anyway)
        setJumpToDefaultPort(true);


        // Insert the cells via the cache, so they get selected
        getGraphLayoutCache().insert(elementosObj);

    }

    /**
     *
     */
    private void miLayout() {
        JGraphFacade facade = new JGraphFacade(this);
        facade.setDirected(true);

        JGraphOrganicLayout layout = new JGraphOrganicLayout();
        layout.setOptimizeEdgeDistance(true);
        layout.setEdgeCrossingCostFactor(500000);
        layout.setOptimizeEdgeDistance(true);
        layout.setEdgeDistanceCostFactor(5000);

        layout.run(facade);
        Map nested = facade.createNestedMap(true, true);
        getGraphLayoutCache().edit(nested);

    }

    /**
     * FUNCIONES AUXILIARES PARA CONVERTIR DE UN AUTOMATA A UN JGRAPH
     */
    private void incluirAristasNodo(Nodo Nodo) {

        // Crear un "cell" para el Nodo
        DefaultGraphCell origen = createCell(Nodo, width * automata.getNodos().cantidad() / 2, 250);
        double x = 0;
        double y;
        for (Arista link : Nodo.getAristas()) {
            if (Nodo.getAristas().indexOf(link) % 2 == 0) {
                y = 50;
            } else {
                y = 450;
            }

            DefaultGraphCell destino = createCell(link.getNodoDestino(), x, y);
            DefaultGraphCell currentLink = createEdge(link, origen, destino);
            x = x + width;
        }
    }

    private DefaultGraphCell createCell(Nodo Nodo, double x, double y) {
        DefaultGraphCell cell = obtenerNodo(Nodo);
        if (cell == null) {
            cell = new DefaultGraphCell(Nodo);
            GraphConstants.setBounds(cell.getAttributes(), new Rectangle2D.Double(x, y, width, height));
            GraphConstants.setBorder(cell.getAttributes(), BorderFactory.createRaisedBevelBorder());
            GraphConstants.setOpaque(cell.getAttributes(), true);
            GraphConstants.setGradientColor(cell.getAttributes(), Color.BLUE);
            cell.addPort(new Point2D.Double(0, 0));

            //Agregamos al la lista
            cells.add(cell);
        }
        return cell;
    }

    private DefaultGraphCell createEdge(Arista Arista, DefaultGraphCell source, DefaultGraphCell target) {
        DefaultEdge edge = new DefaultEdge(Arista);
        source.addPort();
        edge.setSource(source.getChildAt(source.getChildCount() - 1));
        target.addPort();
        edge.setTarget(target.getChildAt(target.getChildCount() - 1));
        GraphConstants.setLabelAlongEdge(edge.getAttributes(), true);
        GraphConstants.setLineEnd(edge.getAttributes(), GraphConstants.ARROW_CLASSIC);
        cells.add(edge);
        return edge;
    }

    /**
     * FUNCIONES PARA ACCEDER A LOS ELEMENTOS
     */
    private DefaultGraphCell obtenerNodo(Nodo Nodo) {

        for (DefaultGraphCell oneCell : cells) {
            if (oneCell.getUserObject() instanceof Nodo && oneCell != null) {
                if (((Nodo) oneCell.getUserObject()).getId() == Nodo.getId()) {
                    return oneCell;
                }
            }
        }
        return null;
    }

}
